package com.fly.lambda.framework.dao;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.util.Assert;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by Fly on 2016/7/14.
 */
@SuppressWarnings("unchecked")
public class BaseDAO<T> {

    @Autowired
    @Qualifier("sessionFactory")
    private SessionFactory sessionFactory;

    protected final Log logger = LogFactory.getLog(getClass());

    /**
     * 返回此Dao所管理的Entity类型
     */
    protected Class<T> poClass;

    public BaseDAO() {
        poClass = (Class<T>) ((ParameterizedType) getClass()
                .getGenericSuperclass()).getActualTypeArguments()[0];
    }

    public Session getSession(){
        return this.sessionFactory.getCurrentSession();
    }

    /**
     * 保存对象
     * @param p
     */
    public void create(T p){
        getSession().save(p);
    }

    /**
     * 更新对象
     * @param p
     */
    public void update(T p){
        getSession().update(p);
    }

    /**
     * 通过Id获取对象
     * @param id
     * @return
     */
    public T getById(Serializable id){
        return (T)getSession().get(this.poClass, id);
    }

    /**
     * 通过Id删除数据
     * @param id
     */
    public void deleteById(Serializable id){

        getSession().delete(getById(id));
    }

    /**
     * 查询总记录数
     * @param hql
     * @param cacheabled
     * @param values
     * @return
     */
    public int count(String hql, boolean cacheabled, Object ...values){
        StringBuilder countHql = new StringBuilder("select count(*) ");
        countHql.append(removeSelect(removeOrders(hql)));
        Query query = getSession().createQuery(hql.toString());
        for(int i = 0; i < values.length; i++){
            query.setParameter(i, values[i]);
        }
        return (Integer)query.uniqueResult();
    }

    /**
     * 获取所有对象
     * @return
     */
    public List<T> getList(){
        String hql = "from " + poClass.getName();
        Query query = getSession().createQuery(hql);
        query.setCacheable(true);
        return query.list();
    }

    /**
     * 按排序获取所有对象
     * @param orderBy
     * @return
     */
    public List<T> getList(String orderBy){
        String hql = "from " + poClass.getName() + " order by " + orderBy;
        Query query = getSession().createQuery(hql);
        query.setCacheable(true);
        return query.list();
    }

    /**
     * 查询对象
     * @param hql
     * @param cacheabled
     * @param values
     * @return
     */
    public List<T> doQueryList(String hql, boolean cacheabled, Object ...values){
        Query query = getSession().createQuery(hql);
        for(int i = 0; i < values.length; i++){
            query.setParameter(i, values[i]);
        }
        query.setCacheable(cacheabled);
        return query.list();
    }

    /**
     * 按范围查询对象
     * @param hql
     * @param cacheabled
     * @param curPage
     * @param pageSize
     * @param values
     * @return
     */
    public List<T> doQueryLimitList(String hql, boolean cacheabled, int curPage, int pageSize, Object ...values){
        Query query = getSession().createQuery(hql);
        for(int i = 0; i < values.length; i++){
            query.setParameter(i, values[i]);
        }
        query.setCacheable(cacheabled);
        if (curPage < 1){
            curPage = 1;
        }
        query.setFirstResult((curPage - 1) * pageSize);
        query.setMaxResults(pageSize);
        return query.list();
    }

    public T doQueryUnique(String hql, boolean cacheabled, Object ...values){
        Query query = getSession().createQuery(hql);
        for(int i = 0; i < values.length; i++){
            query.setParameter(i, values[i]);
        }
        query.setCacheable(cacheabled);
        return (T)query.uniqueResult();
    }

    /**
     * 分页查询对象
     * @param hql
     * @param cacheabled
     * @param curPage
     * @param pageSize
     * @param values
     * @return
     */
    public Pagination<T> doQueryPage(String hql, boolean cacheabled, int curPage, int pageSize, Object ...values){
        StringBuilder totalHql = new StringBuilder("select count(*) ");
        totalHql.append(removeSelect(removeOrders(hql)));
        Query totalQuery = getSession().createQuery(totalHql.toString());
        Query selectQuery = getSession().createQuery(hql);
        for(int i = 0; i < values.length; i++){
            totalQuery.setParameter(i, values[i]);
            selectQuery.setParameter(i, values[i]);
        }
        int total = Integer.parseInt(totalQuery.uniqueResult().toString());
        if (curPage < 1){
            curPage = 1;
        }
        selectQuery.setFirstResult((curPage - 1) * pageSize);
        selectQuery.setMaxResults(pageSize);
        List<T> resultList = selectQuery.list();
        Pagination<T> pagination = new Pagination<T>(resultList, total, curPage, pageSize);
        return pagination;
    }

    /*
     * 去除select 子句，未考虑union的情况
     *
     */
    private static String removeSelect(String hql) {
        Assert.hasText(hql);
        int beginPos = hql.toLowerCase().indexOf("from");
        Assert.isTrue(beginPos != -1, " hql : " + hql + " must has a keyword 'from'");
        return hql.substring(beginPos);
    }

    /*
     * 去除orderby 子句
     */
    private static String removeOrders(String hql) {
        Assert.hasText(hql);
        Pattern p = Pattern.compile("order\\s*by[\\w|\\W|\\s|\\S]*", Pattern.CASE_INSENSITIVE);
        Matcher m = p.matcher(hql);
        StringBuffer sb = new StringBuffer();
        while (m.find()) {
            m.appendReplacement(sb, "");
        }
        m.appendTail(sb);
        return sb.toString();
    }
}
